/*
 * ! ******************************************************************************
 *
 * Pentaho Data Integration
 *
 * Copyright (C) 2002-2017 by Hitachi Vantara : http://www.pentaho.com
 *
 *******************************************************************************
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 *
 ******************************************************************************/

package org.pentaho.di.core.plugins;

import java.io.File;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.annotation.IncompleteAnnotationException;
import java.net.URL;
import java.util.List;

import org.pentaho.di.core.Const;
import org.pentaho.di.core.database.DatabaseInterface;
import org.pentaho.di.core.exception.KettlePluginException;
import org.pentaho.di.core.exception.KettleXMLException;
import org.pentaho.di.core.xml.XMLHandler;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.yzbdl.lanius.core.plugins.ClassLoaderCfg;
import org.yzbdl.lanius.core.plugins.annotations.ClassLoaderAnno;
import org.yzbdl.lanius.core.plugins.install.PluginLoader;
import org.yzbdl.lanius.core.plugins.metastore.LdrPluginEntity;
import org.yzbdl.lanius.core.plugins.service.PluginService;

import cn.hutool.core.util.StrUtil;

/**
 * This class represents the step plugin type.
 *
 * @author matt
 *
 */
@PluginMainClassType(DatabaseInterface.class)
@PluginAnnotationType(DatabaseMetaPlugin.class)
public class DatabasePluginType extends BasePluginType implements PluginTypeInterface {
    private static DatabasePluginType pluginType;

    private DatabasePluginType() {
        super(DatabaseMetaPlugin.class, "DATABASE", "Database");
        populateFolders("databases");
    }

    public static DatabasePluginType getInstance() {
        if (pluginType == null) {
            pluginType = new DatabasePluginType();
        }
        return pluginType;
    }

    @Override
    protected void registerFromDb() throws KettlePluginException {
        List<LdrPluginEntity> stepPlugins = PluginService.getInstance().getLocalPlugins(DatabasePluginType.class);
        for (LdrPluginEntity ldrPluginEntity : stepPlugins) {
            if (new File("plugins" + File.separator + ldrPluginEntity.getFolderName()).exists()
                && new File("plugins" + File.separator + ldrPluginEntity.getFolderName()).listFiles().length > 0) {
                PluginLoader.loadOne(ldrPluginEntity);
            }
        }
    }

    /**
       * Scan & register internal step plugins
       */
    @Override
    protected void registerNatives() throws KettlePluginException {
        // Scan the native database types...
        //
        String xmlFile = Const.XML_FILE_KETTLE_DATABASE_TYPES;

        // Load the plugins for this file...
        //
        try {
            InputStream inputStream = getClass().getResourceAsStream(xmlFile);
            if (inputStream == null) {
                inputStream = getClass().getResourceAsStream("/" + xmlFile);
            }
            if (inputStream == null) {
                throw new KettlePluginException(
                    "Unable to find native kettle database types definition file: " + xmlFile);
            }
            Document document = XMLHandler.loadXMLFile(inputStream, null, true, false);

            Node repsNode = XMLHandler.getSubNode(document, "database-types");
            List<Node> repsNodes = XMLHandler.getNodes(repsNode, "database-type");
            for (Node repNode : repsNodes) {
                registerPluginFromXmlResource(repNode, "./", this.getClass(), true, null);
            }
        } catch (KettleXMLException e) {
            throw new KettlePluginException("Unable to read the kettle database types XML config file: " + xmlFile, e);
        }
    }

    @Override
    protected void registerXmlPlugins() throws KettlePluginException {}

    @Override
    public void handlePluginAnnotation(Class<?> clazz, Annotation annotation, List<String> libraries,
        boolean nativePluginType, URL pluginFolder) throws KettlePluginException {
        // TODO Auto-generated method stub
        super.handlePluginAnnotation(clazz, annotation, libraries, nativePluginType, pluginFolder);
    }

    public String[] getNaturalCategoriesOrder() {
        return new String[0];
    }

    @Override
    protected String extractCategory(Annotation annotation) {
        String category = ((DatabaseMetaPlugin)annotation).category();
        return category;
    }

    @Override
    protected String extractDesc(Annotation annotation) {
        return ((DatabaseMetaPlugin)annotation).typeDescription();
    }

    @Override
    protected String extractID(Annotation annotation) {
        String id = null;

        try {
            id = ((DatabaseMetaPlugin)annotation).id();
        } catch (IncompleteAnnotationException e) {
        }

        if (StrUtil.isBlank(id)) {
            id = ((DatabaseMetaPlugin)annotation).type();
        }
        return id;
    }

    @Override
    protected String extractName(Annotation annotation) {
        String name = null;

        try {
            name = ((DatabaseMetaPlugin)annotation).name();
        } catch (IncompleteAnnotationException e) {
        }

        if (StrUtil.isBlank(name)) {
            name = ((DatabaseMetaPlugin)annotation).typeDescription();
        }
        return name;
    }

    @Override
    protected String extractImageFile(Annotation annotation) {
        return ((DatabaseMetaPlugin)annotation).image();
    }

    @Override
    protected boolean extractSeparateClassLoader(Annotation annotation) {
        return false;
    }

    @Override
    protected String extractI18nPackageName(Annotation annotation) {
        return null;
    }

    @Override
    protected String extractSuggestion(Annotation annotation) {
        return null;
    }

    @Override
    protected String extractCasesUrl(Annotation annotation) {
        return null;
    }

    @Override
    protected String extractForumUrl(Annotation annotation) {
        return null;
    }

    @Override
    protected String extractClassLoaderGroup(Annotation annotation) {
        return ((DatabaseMetaPlugin)annotation).classLoaderGroup();
    }

    @Override
    protected String extractVersion(Annotation annotation) {
        return ((DatabaseMetaPlugin)annotation).version();
    }

    @Override
    protected boolean extractEnterprise(Annotation annotation) {
        return ((DatabaseMetaPlugin)annotation).enterprise();
    }

    @Override
    protected ClassLoaderCfg extractClassLoaderAnno(Annotation annotation) {
        ClassLoaderAnno clAnno = ((DatabaseMetaPlugin)annotation).classLoader();
        ClassLoaderCfg clVo = new ClassLoaderCfg();
        clVo.setIsSeparateClassLoaderNeeded(clAnno.isSeparateClassLoaderNeeded());
        clVo.setUserDefinedGroup(clAnno.userDefinedGroup());
        clVo.setFolderBasedGroup(clAnno.folderBasedGroup());
        return clVo;
    }
}
